{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Budget accounting with diffprivlib"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Diffprivlib includes a budget accountant to allow you to keep track of privacy budget being spent. The budget accounting is handled by the `BudgetAccountant` class."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Basic functionality of the `BudgetAccountant` includes initialisation with an appropriate `epsilon` and `delta` (if desired), determining the total current spend with `total()` and evaluating the remaining budget to be spent with `remaining()`. The number of recorded budget spends can be found using `len()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from numpy.random import random\n",
    "from diffprivlib import BudgetAccountant\n",
    "from diffprivlib.tools import mean, var\n",
    "\n",
    "X = random(100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total spent: (epsilon=1.0, delta=0.0)\n",
      "Remaining budget (for 1 query): (epsilon=4.0, delta=0.0)\n",
      "Remaining budget (for 4 queries): (epsilon=1.0, delta=0.0)\n",
      "Number of queries recorded: 1\n"
     ]
    }
   ],
   "source": [
    "acc = BudgetAccountant(epsilon=5, delta=0)\n",
    "dp_mean = mean(X, bounds=(0, 1), accountant=acc)\n",
    "\n",
    "print(\"Total spent: %r\" % (acc.total(),))\n",
    "print(\"Remaining budget (for 1 query): %r\" % (acc.remaining(),))\n",
    "print(\"Remaining budget (for 4 queries): %r\" % (acc.remaining(4),))\n",
    "print(\"Number of queries recorded: %d\" % len(acc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If a query were to exceed the privacy budget specified in the accountant, an error is raised and execution ceases."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Error raised <class 'diffprivlib.utils.BudgetError'>: Privacy spend of (1,0) not permissible; will exceed remaining privacy budget. Use BudgetAccountant.remaining() to check remaining budget.\n"
     ]
    }
   ],
   "source": [
    "acc = BudgetAccountant(1.5, 0)\n",
    "\n",
    "dp_mean = mean(X, epsilon=1, bounds=(0, 1), accountant=acc)\n",
    "\n",
    "try:\n",
    "    dp_std = var(X, epsilon=1, bounds=(0, 1), accountant=acc)\n",
    "except Exception as e:\n",
    "    print(\"Error raised {}: {}\".format(type(e), e))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using `BudgetAccountant` to track privacy budget"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are three ways to use the `BudgetAccountant` class to track budget spend across many operations:\n",
    "1. **Parametrisation:** Passed as a parameter (`accountant=acc`)\n",
    "2. **Default:** Set as a default (`set_default()`)\n",
    "3. **Context manager:** Using \"`with`\" over a block of code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total spend: (epsilon=1.618, delta=0.0)\n"
     ]
    }
   ],
   "source": [
    "acc_p = BudgetAccountant()\n",
    "mean(X, epsilon=1.618, bounds=(0, 1), accountant=acc_p)\n",
    "\n",
    "print(\"Total spend: %r\" % (acc_p.total(),))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total spend: (epsilon=2.718, delta=0.0)\n"
     ]
    }
   ],
   "source": [
    "acc_d = BudgetAccountant()\n",
    "acc_d.set_default()\n",
    "mean(X, epsilon=2.718, bounds=(0, 1))\n",
    "\n",
    "print(\"Total spend: %r\" % (acc_d.total(),))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total spend: (epsilon=3.141, delta=0.0)\n"
     ]
    }
   ],
   "source": [
    "with BudgetAccountant() as acc_w:\n",
    "    mean(X, epsilon=1.5705, bounds=(0, 1))\n",
    "    var(X, epsilon=1.5705, bounds=(0, 1))\n",
    "\n",
    "print(\"Total spend: %r\" % (acc_w.total(),))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Setting the `slack`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Composition of privacy budgets typically add up linearly, that is unless you allow a slack in your `delta`. This is governed by the `slack` parameter in the initialisation.\n",
    "\n",
    "The benefit of a non-zero slack is especially evident when many queries are being asked."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f8eff991e10>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "acc_n = BudgetAccountant()\n",
    "acc_a = BudgetAccountant(slack=1e-3)\n",
    "epsilon, queries = 2**-6, 30\n",
    "\n",
    "budget_naive = [0] + [acc_n.spend(epsilon, 0).total()[0] for i in range(queries)]\n",
    "budget_advanced = [0] + [acc_a.spend(epsilon, 0).total()[0] for i in range(queries)]\n",
    "\n",
    "plt.plot(range(queries + 1), budget_naive, label=\"Naive composition (slack=%g)\" % acc_n.slack)\n",
    "plt.plot(range(queries + 1), budget_advanced, label=\"Advanced composition (slack=%g)\" % acc_a.slack)\n",
    "plt.xlabel(\"Queries\")\n",
    "plt.ylabel(\"Epsilon spent\")\n",
    "plt.xlim(0, queries)\n",
    "plt.ylim(0, None)\n",
    "plt.legend()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
